lckj:
    const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

// 输入输出处理
void (async function () {
    console.log(getResult(await readline()));
})();

// 分数
class Fractions {
    constructor(fa, ch) {
        this.fa = fa; // 分母
        this.ch = ch; // 分子
    }
}

// 操作数栈
const oper_num = [];
// 操作符栈
const oper_sign = [];

function getResult(s) {
    // +,-,*,/ 运算符优先级
    const priority = {
        "+": 1,
        "-": 1,
        "*": 2,
        "/": 2,
    };

    // 操作数的字符缓存容器
    let numStr = [];

    let i = 0;
    while (i < s.length) {
        let c = s[i];

        // 遇到数字字符
        if (c >= "0" && c <= "9") {
            // 则将该数字所在操作数的剩余数字字符一次性探索完
            while (c >= "0" && c <= "9") {
                numStr.push(c);
                if (i + 1 >= s.length) break;
                i++;
                c = s[i];
            }

            // 探索完后，将操作数缓存容器中记录的字符，变为分数后，压入操作数栈
            oper_num.push(new Fractions(1, parseInt(numStr.join(""))));
            // 注意清空操作数缓存容器
            numStr.length = 0;
        }

        // 遇到运算符
        if (c == "+" || c == "-" || c == "*" || c == "/") {
            // 只要栈顶运算符的优先级 >= 当前运算符，就需要不停出栈运算
            while (
                oper_sign.length > 0 &&
                oper_sign.at(-1) != "(" &&
                priority[c] <= priority[oper_sign.at(-1)]
                ) {
                calc();
            }
            oper_sign.push(c);
        } else if (c == ")") {
            // 遇到')', 需要将操作符栈中靠近栈顶的'('后面的运算都出栈做了
            while (oper_sign.at(-1) != "(") {
                calc();
            }
            // 最后将')'对应的'('出栈
            oper_sign.pop();
        } else if (c == "(") {
            // 遇到'('，则直接压倒操作符栈
            oper_sign.push(c);
        }

        i++;
    }

    // oper_num栈中还有2个以上的数，则还需要进行运算
    while (oper_num.length > 1) {
        calc();
    }

    // oper_num栈中只剩一个数时，该数就是表达式结果
    const result = oper_num.pop();

    // 如果结果的分母为0（除数为0），则不合法
    if (result.fa == 0) {
        return "ERROR";
    }

    // 求分子、分母的最大公约数，并进行约份，求得最简格式的分子，分母
    const k = getMaxCommonDivisor(result.fa, result.ch);
    result.fa /= k;
    result.ch /= k;

    // 求计算结果的符号，这里用乘法是为了避免 分母小，分子大，除法结果为0的情况，这样会丢失符号信息
    const sign = result.fa * result.ch < 0 ? "-" : "";

    const fa = Math.abs(result.fa);
    const ch = Math.abs(result.ch);

    if (fa == 1) {
        // 如果分母为1，则直接输出分子
        return sign + ch;
    } else {
        // 如果分母不为1，则输出 分子 / 分母
        return sign + ch + "/" + fa;
    }
}

// 取出oper_num栈顶两个操作数进行运算
function calc() {
    // 操作数顺序会对运算产生影响
    const b = oper_num.pop(); // 栈顶元素是运算符右边的操作数
    const a = oper_num.pop(); // 栈顶倒数第二个元素是运算符左边的操作数

    // 运算符
    const op = oper_sign.pop();

    // 记录运算结果
    const result = new Fractions();

    switch (op) {
        case "+":
            result.fa = a.fa * b.fa;
            result.ch = a.ch * b.fa + b.ch * a.fa;
            break;
        case "-":
            result.fa = a.fa * b.fa;
            result.ch = a.ch * b.fa - b.ch * a.fa;
            break;
        case "*":
            result.fa = a.fa * b.fa;
            result.ch = a.ch * b.ch;
            break;
        case "/":
            result.fa = a.fa * b.ch;
            result.ch = a.ch * b.fa;
            break;
    }

    oper_num.push(result);
}

// 辗转相除法，求两个数的最大公约数
function getMaxCommonDivisor(x, y) {
    while (y != 0) {
        let tmp = y;
        y = x % y;
        x = tmp;
    }

    return x;
}
